package org.gd.exercise.learnspringbootredis.controller;

import org.gd.exercise.learnspringbootredis.dto.WbNewsRankingDTO;
import org.gd.exercise.learnspringbootredis.dto.WbNewsRankingListDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author name: yushanjiang
 * @version 1.0
 * @description: Redis数据类型-ZSet应用场景-微博热搜新闻
 * @date 2025/9/15 8:35
 */
@RestController
@RequestMapping("/zset")
public class ZSetController {
    @Autowired
    private RedisTemplate redisTemplate;
    // 日期格式化器
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");

    /**
    * @description: 点击新闻，点击量加一
    * @param: [newsTitle]
    * @return java.lang.String
    * @author name: yushanjiang
    * @date: 2025/9/15 9:23
    */
    @PostMapping("/wbnews/click/{newsTitle}")
    public String click(@PathVariable String newsTitle) {
        String today = LocalDate.now().format(formatter);
        // 分别为当天新闻和7日新闻设置key
        String daily_key = "jys_wbnews:daiy:" + today;
        String total_key = "jys_wbnews:total:";

        // 设置7日新闻过期时间为8天，保证7日新闻都能被统计;
        // 将新闻在两个key中的点击量分别加一
        redisTemplate.expire(total_key, 8, TimeUnit.DAYS);
        redisTemplate.opsForZSet().incrementScore(daily_key, newsTitle, 1);
        redisTemplate.opsForZSet().incrementScore(total_key, newsTitle, 1);

        // 获取当前点击量
        Double currentScore = redisTemplate.opsForZSet().score(daily_key, newsTitle);

        return "点击新闻[" + newsTitle + "]，该新闻当前点击量为：" + currentScore;
    }
    
    /**
    * @description: 返回当日点击量top10的新闻
    * @param: [date]
    * @return java.util.Set
    * @author name: yushanjiang
    * @date: 2025/9/15 9:57
    */
    @GetMapping("/wbnews/daily/top10")
    public WbNewsRankingListDTO getDailyTop10(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date)  {
        String key = "jys_wbnews:daiy:" + date.format(formatter);

        WbNewsRankingListDTO response = new WbNewsRankingListDTO();
        response.setSuccess(true);

        List<WbNewsRankingDTO> newsList = new ArrayList<>();

        Set<ZSetOperations.TypedTuple<Object>> redisResult = redisTemplate.opsForZSet()
                .reverseRangeWithScores(key, 0, 9);

        if (redisResult != null && redisResult.size() > 0) {
            int rank = 1;
            for (ZSetOperations.TypedTuple<Object> tuple : redisResult) {
                WbNewsRankingDTO dto = new WbNewsRankingDTO();
                dto.setNewsTitle(tuple.getValue().toString());
                dto.setRank(rank++);
                dto.setScore(tuple.getScore());

                newsList.add(dto);
            }
        }
        response.setData(newsList);
        response.setTotal(redisResult.size());
        return response;
    }
    
    @GetMapping("/wbnews/weekly/top10")
    public WbNewsRankingListDTO getWeeklyTop10() {
        // 计算过去7天日期
        LocalDate today = LocalDate.now();
        List<String> dailyKeys = new ArrayList<>();

        String weeklyTempKey = "jys_wbnews:weekly:temp" + System.currentTimeMillis();

        for(int i = 1; i <= 7; i++) {
            dailyKeys.add("jys_wbnews:daiy:" + today.format(formatter));
            today = today.minusDays(i);
        }

        List<WbNewsRankingDTO> weeklyTop10List = new ArrayList<>();

        for (String dailyKey : dailyKeys) {
            if(redisTemplate.hasKey(dailyKey)) {
                // 获取当日所有新闻
                Set<ZSetOperations.TypedTuple<Object>> entries = redisTemplate
                        .opsForZSet().reverseRangeWithScores(dailyKey, 0, -1);

                for(ZSetOperations.TypedTuple<Object> tuple : entries) {
                    // 将当日所有新闻添加到redis的临时key中，汇总这七天的所有新闻
                    redisTemplate.opsForZSet().add(
                            weeklyTempKey,
                            tuple.getValue(),
                            tuple.getScore());
                }
            }
        }

        //将weeklyTempKey中所有新闻按score排序，得到weeklyt top10新结果集
        Set<ZSetOperations.TypedTuple<Object>> weeklyEntries = redisTemplate
                .opsForZSet().reverseRangeWithScores(weeklyTempKey, 0, 9);

        for (ZSetOperations.TypedTuple<Object> tuple : weeklyEntries) {
            WbNewsRankingDTO newsDTO = new WbNewsRankingDTO();
            newsDTO.setNewsTitle(tuple.getValue().toString());
            newsDTO.setScore(tuple.getScore());
            weeklyTop10List.add(newsDTO);
        }

        WbNewsRankingListDTO response = new WbNewsRankingListDTO();
        response.setSuccess(true);
        response.setTotal(weeklyTop10List.size());
        response.setData(weeklyTop10List);
        return response;
    }

    @GetMapping("/wbnews/weekly/list")
    public WbNewsRankingListDTO getWeeklyList() {
        // 计算过去7天日期
        LocalDate today = LocalDate.now();
        List<String> dailyKeys = new ArrayList<>();

        String weeklyTempKey = "jys_wbnews:weekly:temp" + System.currentTimeMillis();

        for(int i = 1; i <= 7; i++) {
            dailyKeys.add("jys_wbnews:daiy:" + today.format(formatter));
            today = today.minusDays(i);
        }

        List<WbNewsRankingDTO> weeklyTop10List = new ArrayList<>();

        for (String dailyKey : dailyKeys) {
            if(redisTemplate.hasKey(dailyKey)) {
                // 获取当日所有新闻
                Set<ZSetOperations.TypedTuple<Object>> entries = redisTemplate
                        .opsForZSet().reverseRangeWithScores(dailyKey, 0, -1);

                for(ZSetOperations.TypedTuple<Object> tuple : entries) {
                    // 将当日所有新闻添加到redis的临时key中，汇总这七天的所有新闻
                    redisTemplate.opsForZSet().add(
                            weeklyTempKey,
                            tuple.getValue(),
                            tuple.getScore());
                }
            }
        }

        //将weeklyTempKey中所有新闻按score排序，得到weekly新结果集
        // 和上个方法的区别仅在于排序的end坐标
        Set<ZSetOperations.TypedTuple<Object>> weeklyEntries = redisTemplate
                .opsForZSet().reverseRangeWithScores(weeklyTempKey, 0, -1);

        for (ZSetOperations.TypedTuple<Object> tuple : weeklyEntries) {
            WbNewsRankingDTO newsDTO = new WbNewsRankingDTO();
            newsDTO.setNewsTitle(tuple.getValue().toString());
            newsDTO.setScore(tuple.getScore());
            weeklyTop10List.add(newsDTO);
        }

        WbNewsRankingListDTO response = new WbNewsRankingListDTO();
        response.setSuccess(true);
        response.setTotal(weeklyTop10List.size());
        response.setData(weeklyTop10List);
        return response;
    }
}
